package algorithm.sort;

import org.junit.Before;
import org.junit.Test;

import java.util.Arrays;

/**
 * 堆排序
 */
public class HeapSort {

    private final int[] arr = new int[15];

    @Before
    public void init() {
        for (int i = 0, j = arr.length; i < arr.length; i++) {
            arr[i] = (int) (Math.random() * j);
        }
    }

    /**
     * 升序排列
     * 1. 构建大顶堆
     * 2. 堆定
     */
    @Test
    public void sort() {
        System.out.println("排序前:" + Arrays.toString(arr));
        //1.构建大顶堆
        for (int i = arr.length / 2 - 1; i >= 0; i--) {
            //从第一个非叶子结点从下至上，从右至左调整结构
            adjustHeap(i, arr.length);
        }
        //2.调整堆结构+交换堆顶元素与末尾元素
        for (int j = arr.length - 1; j > 0; j--) {
            //将堆顶元素与末尾元素进行交换
            arr[0] = arr[0] ^ arr[j];
            arr[j] = arr[0] ^ arr[j];
            arr[0] = arr[0] ^ arr[j];
            //重新对堆进行调整
            adjustHeap(0, j);
        }
        System.out.println("排序后:" + Arrays.toString(arr));
    }

    /**
     * 调整大顶堆（仅是调整过程，建立在大顶堆已构建的基础上）
     */
    private void adjustHeap(int i, int length) {
        //先取出当前元素i
        int temp = arr[i];
        //从i结点的左子结点开始，也就是2i+1处开始
        for (int k = i * 2 + 1; k < length; k = k * 2 + 1) {
            //如果左子结点小于右子结点，k指向右子结点
            if (k + 1 < length && arr[k] < arr[k + 1]) {
                k++;
            }
            //如果子节点大于父节点，将子节点值赋给父节点（不用进行交换）
            if (arr[k] > temp) {
                arr[i] = arr[k];
                i = k;
            } else {
                break;
            }
        }
        //将temp值放到最终的位置
        arr[i] = temp;
    }

}
